

#include <gdt.h>
#include <debug.h>

#define ENTRIES 3

static gdt_entry_t gdt[ENTRIES];
gdt_ptr_t gp;

void gdt_set_gate(int index, dword base, dword limit, byte access, byte flags)
{
    gdt[index].base_low = (base & 0xFFFF);
    gdt[index].base_middle = (base >> 16) & 0xFF;
    gdt[index].base_high = (base >> 24) & 0xFF;

    gdt[index].limit_low = (limit & 0xFFFF);
    gdt[index].flags = ((limit >> 16) & 0x0F);

	gdt[index].flags |= (flags & 0xF0);
    gdt[index].access = access;
}

void init_gdt(void)
{
	gp.limit = (sizeof(gdt_entry_t) * ENTRIES) - 1;
    gp.base = (dword)&gdt;
    
    gdt_set_gate(0, 0, 0, 0, 0);
    
    gdt_set_gate(1, 0, 0xFFFFFFFF, (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_EXEC | GDT_ACCESS_RING0),
     (GDT_FLAGS_4K | GDT_FLAGS_32BIT));
    
    gdt_set_gate(2, 0, 0xFFFFFFFF, (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_DATA | GDT_ACCESS_RING0),
     (GDT_FLAGS_4K | GDT_FLAGS_32BIT));
     
    //gdt_set_gate(3, 0, 0xFFFFFFFF, (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_EXEC | GDT_ACCESS_RING3),
    // (GDT_FLAGS_4K | GDT_FLAGS_32BIT));
    
    //gdt_set_gate(4, 0, 0xFFFFFFFF, (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_DATA | GDT_ACCESS_RING3),
    // (GDT_FLAGS_4K | GDT_FLAGS_32BIT));
    
    /*
    debugf("1(access): %d\n", (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_EXEC | GDT_ACCESS_RING0));
    debugf("1(flags): %d\n", (FLAGS_4K | FLAGS_32BIT));
    debugf("2/3(access): %d\n", (GDT_ACCESS | GDT_ACCESS_RW | GDT_ACCESS_UP | GDT_ACCESS_DATA | GDT_ACCESS_RING0));
     */
     
    gdt_install();
    
    debugf("GDT: Installed @ 0x%08x\n", gdt);
    debugf("GDT: Pointer @ 0x%08x\n", &gp);
}

void gdt_install(void)
{
	__gdt_install();
}
